#include <stx/test/test.hpp>

TEST_CASE (core_algo)
{
    {
        CHECK(startsWith("Hello"s, "He"));
        CHECK(startsWith("Hello"s, "Hello"));
        CHECK(!startsWith("Hello"s, "Hello2"));

        CHECK(startsWith("Hello"s, "He"s));
        CHECK(startsWith("Hello"s, "Hello"s));
        CHECK(!startsWith("Hello"s, "Hello2"s));

        CHECK(startsWith("Hello"s, "He"sv));
        CHECK(startsWith("Hello"s, "Hello"sv));
        CHECK(!startsWith("Hello"s, "Hello2"sv));

        CHECK(startsWith("Hello", "He"));
        CHECK(startsWith("Hello", "Hello"));
        CHECK(!startsWith("Hello", "Hello2"));

        CHECK(startsWith("Hello", "He"s));
        CHECK(startsWith("Hello", "Hello"s));
        CHECK(!startsWith("Hello", "Hello2"s));

        CHECK(startsWith("Hello", "He"sv));
        CHECK(startsWith("Hello", "Hello"sv));
        CHECK(!startsWith("Hello", "Hello2"sv));

        CHECK(startsWith("Hello"sv, "He"));
        CHECK(startsWith("Hello"sv, "Hello"));
        CHECK(!startsWith("Hello"sv, "Hello2"));

        CHECK(startsWith("Hello"sv, "He"s));
        CHECK(startsWith("Hello"sv, "Hello"s));
        CHECK(!startsWith("Hello"sv, "Hello2"s));

        CHECK(startsWith("Hello"sv, "He"sv));
        CHECK(startsWith("Hello"sv, "Hello"sv));
        CHECK(!startsWith("Hello"sv, "Hello2"sv));
    }

    {
        CHECK(endsWith("Hello"s, "llo"));
        CHECK(endsWith("Hello"s, "Hello"));
        CHECK(!endsWith("Hello"s, "Hello2"));
        CHECK(!endsWith("2Hello"s, "Hello2"));

        CHECK(endsWith("Hello"s, "llo"s));
        CHECK(endsWith("Hello"s, "Hello"s));
        CHECK(!endsWith("Hello"s, "Hello2"s));
        CHECK(!endsWith("2Hello"s, "Hello2"s));

        CHECK(endsWith("Hello"s, "llo"sv));
        CHECK(endsWith("Hello"s, "Hello"sv));
        CHECK(!endsWith("Hello"s, "Hello2"sv));
        CHECK(!endsWith("2Hello"s, "Hello2"sv));

        CHECK(endsWith("Hello", "llo"));
        CHECK(endsWith("Hello", "Hello"));
        CHECK(!endsWith("Hello", "Hello2"));
        CHECK(!endsWith("2Hello", "Hello2"));

        CHECK(endsWith("Hello", "llo"s));
        CHECK(endsWith("Hello", "Hello"s));
        CHECK(!endsWith("Hello", "Hello2"s));
        CHECK(!endsWith("2Hello", "Hello2"s));

        CHECK(endsWith("Hello", "llo"sv));
        CHECK(endsWith("Hello", "Hello"sv));
        CHECK(!endsWith("Hello", "Hello2"sv));
        CHECK(!endsWith("2Hello", "Hello2"sv));

        CHECK(endsWith("Hello"sv, "llo"));
        CHECK(endsWith("Hello"sv, "Hello"));
        CHECK(!endsWith("Hello"sv, "Hello2"));
        CHECK(!endsWith("2Hello"sv, "Hello2"));

        CHECK(endsWith("Hello"sv, "llo"s));
        CHECK(endsWith("Hello"sv, "Hello"s));
        CHECK(!endsWith("Hello"sv, "Hello2"s));
        CHECK(!endsWith("2Hello"sv, "Hello2"s));

        CHECK(endsWith("Hello"sv, "llo"sv));
        CHECK(endsWith("Hello"sv, "Hello"sv));
        CHECK(!endsWith("Hello"sv, "Hello2"sv));
        CHECK(!endsWith("2Hello"sv, "Hello2"sv));
    }

    {
        auto coll = std::stack<int>{};
        LOOP (i, 100)
        {
            insert(coll, i);
        }

        LOOP (i, 100)
        {
            CHECK(!coll.empty());
            CHECK(99 - i == coll.top());
            coll.pop();
        }

        CHECK(coll.empty());

        splice(coll, std::vector{1, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 5);
        CHECK(coll.top() == 5);
        coll.pop();
        CHECK(coll.top() == 4);
        coll.pop();
        CHECK(coll.top() == 3);
        coll.pop();
        CHECK(coll.top() == 2);
        coll.pop();
        CHECK(coll.top() == 1);
        coll.pop();
        CHECK(coll.empty());

        auto coll2 = std::stack<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = std::queue<int>{};
        LOOP (i, 100)
        {
            insert(coll, i);
        }

        LOOP (i, 100)
        {
            CHECK(!coll.empty());
            CHECK(i == coll.front());
            coll.pop();
        }

        CHECK(coll.empty());

        splice(coll, std::vector{1, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 5);
        CHECK(coll.front() == 1);
        coll.pop();
        CHECK(coll.front() == 2);
        coll.pop();
        CHECK(coll.front() == 3);
        coll.pop();
        CHECK(coll.front() == 4);
        coll.pop();
        CHECK(coll.front() == 5);
        coll.pop();
        CHECK(coll.empty());

        auto coll2 = std::queue<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = std::priority_queue<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(1, 10));
        }

        auto last_elem = 11;
        LOOP (i, 100)
        {
            CHECK(!coll.empty());
            CHECK(last_elem >= coll.top());
            last_elem = coll.top();
            coll.pop();
        }

        CHECK(coll.empty());
        splice(coll, std::vector{1, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 5);
        CHECK(coll.top() == 5);
        coll.pop();
        CHECK(coll.top() == 4);
        coll.pop();
        CHECK(coll.top() == 3);
        coll.pop();
        CHECK(coll.top() == 2);
        coll.pop();
        CHECK(coll.top() == 1);
        coll.pop();
        CHECK(coll.empty());

        auto coll2 = std::priority_queue<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = Multiset<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(1, 10));
        }

        auto pos1 = coll.begin();
        auto pos2 = coll.begin();
        ++pos2;

        LOOP (i, 99)
        {
            CHECK(*pos1++ <= *pos2++);
        }

        CHECK(coll.size() == 100);
        coll.clear();

        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 6);

        auto pos = coll.begin();
        CHECK(1 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(5 == *pos);

        auto coll2 = Multiset<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = UnorderedMultiset<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(1, 10));
        }

        CHECK(coll.size() == 100);

        auto const coll2 = coll | ranges::to<Multiset<int>>;
        auto       pos1  = coll2.begin();
        auto       pos2  = coll2.begin();
        ++pos2;

        LOOP (i, 99)
        {
            CHECK(*pos1++ <= *pos2++);
        }

        CHECK(coll.size() == 100);

        coll.clear();
        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 6);

        auto coll3 = UnorderedMultiset<std::string>{};
        auto bufs =
            std::vector{genRandString(1024, 4096), genRandString(3000, 5000)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll3, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = Set<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(1, 10));
        }

        CHECK(!coll.empty());

        auto pos1 = coll.begin();
        auto pos2 = coll.begin();
        ++pos2;

        while (pos2 != coll.end())
        {
            CHECK(*pos1 < *pos2, tos(*pos1), tos(*pos2));
            ++pos1;
            ++pos2;
        }

        coll.clear();

        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 5);

        auto pos = coll.begin();
        CHECK(1 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(5 == *pos);

        auto coll2 = Set<std::string>{};
        auto bufs =
            std::vector{genRandString(1024, 4096), genRandString(3000, 5000)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = UnorderedSet<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(1, 10));
        }

        CHECK(!coll.empty());

        auto const coll2 = coll | ranges::to<Set<int>>;
        auto       pos1  = coll2.begin();
        auto       pos2  = coll2.begin();
        ++pos2;

        while (pos2 != coll2.end())
        {
            CHECK(*pos1++ < *pos2++);
        }

        CHECK(!coll2.empty());

        coll.clear();

        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 5);

        auto coll3 = UnorderedSet<std::string>{};
        auto bufs =
            std::vector{genRandString(1024, 4096), genRandString(3000, 5000)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll3, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = std::string{};
        LOOP (i, 100)
        {
            insert(coll, rand<char>('a', 'z'));
        }
        CHECK(coll.size() == 100);

        coll = "hello"s;
        splice(coll, std::vector{'a', 'b', 'c'}, std::list{'y', 'z'});
        CHECK(coll == "helloabcyz"sv);
    }

    {
        auto coll = std::wstring{};
        LOOP (i, 100)
        {
            insert(coll, rand<wchar_t>(L'a', L'z'));
        }
        CHECK(coll.size() == 100);
    }

    {
        auto coll = std::u8string{};
        LOOP (i, 100)
        {
            insert(coll, rand<char8_t>(u8'a', u8'z'));
        }
        CHECK(coll.size() == 100);
    }

    {
        auto coll = std::u16string{};
        LOOP (i, 100)
        {
            insert(coll, rand<char16_t>(u'a', u'z'));
        }
        CHECK(coll.size() == 100);
    }

    {
        auto coll = std::u32string{};
        LOOP (i, 100)
        {
            insert(coll, rand<char32_t>(U'a', U'z'));
        }
        CHECK(coll.size() == 100);
    }

    {
        auto coll = std::vector<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(1, 100));
        }
        CHECK(coll.size() == 100);
        CHECK(ranges::count_if(coll,
                               [](auto const n)
                               { return n >= 1 && n <= 100; }) == 100);

        coll.clear();
        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 6);
        auto pos = coll.begin();
        CHECK(1 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(5 == *pos);

        auto coll2 = std::vector<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = Buffer{};
        LOOP (i, 100)
        {
            insert(coll, std::byte(rand<std::uint8_t>()));
        }
        CHECK(coll.size() == 100);
        CHECK(ranges::count_if(coll,
                               [](auto const n) {
                                   return n >= std::byte(0uz) &&
                                          n <= std::byte(255uz);
                               }) == 100);

        coll.clear();
        splice(
            coll,
            std::vector{std::byte(1), std::byte(3), std::byte(2), std::byte(3)},
            std::list{std::byte(4), std::byte(5)});
        CHECK(coll.size() == 6);
        auto pos = coll.begin();
        CHECK(std::byte(1) == *pos);
        ++pos;
        CHECK(std::byte(3) == *pos);
        ++pos;
        CHECK(std::byte(2) == *pos);
        ++pos;
        CHECK(std::byte(3) == *pos);
        ++pos;
        CHECK(std::byte(4) == *pos);
        ++pos;
        CHECK(std::byte(5) == *pos);
    }

    {
        auto coll = std::deque<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(0, 255));
        }
        CHECK(coll.size() == 100);
        CHECK(ranges::count_if(coll,
                               [](auto const n)
                               { return n >= 0 && n <= 255; }) == 100);

        coll.clear();
        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 6);
        auto pos = coll.begin();
        CHECK(1 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(5 == *pos);

        auto coll2 = std::deque<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll2, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = std::list<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(0, 255));
        }
        CHECK(coll.size() == 100);
        CHECK(ranges::count_if(coll,
                               [](auto const n)
                               { return n >= 0 && n <= 255; }) == 100);

        coll.clear();
        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        CHECK(coll.size() == 6);
        auto pos = coll.begin();
        CHECK(1 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(5 == *pos);

        auto coll2 = std::list<int>{};
        splice(coll2, std::move(coll), std::vector{7, 8, 9});
        CHECK(coll.empty());
        CHECK(coll2.size() == 9);
        CHECK(ranges::equal(coll2, std::vector{1, 3, 2, 3, 4, 5, 7, 8, 9}));

        auto coll3 = std::stack<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll3, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = std::forward_list<int>{};
        LOOP (i, 100)
        {
            insert(coll, rand(0, 255));
        }
        CHECK(ranges::count_if(coll,
                               [](auto const n)
                               { return n >= 0 && n <= 255; }) == 100);

        coll.clear();
        CHECK(coll.empty());

        splice(coll, std::vector{1, 3, 2, 3}, std::list{4, 5});
        auto pos = coll.begin();
        CHECK(5 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(1 == *pos);

        auto coll2 = std::forward_list<int>{};
        splice(coll2, std::vector{7, 8, 9}, std::move(coll));
        CHECK(coll.empty());

        pos = coll2.begin();
        CHECK(5 == *pos);
        ++pos;
        CHECK(4 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(2 == *pos);
        ++pos;
        CHECK(3 == *pos);
        ++pos;
        CHECK(1 == *pos);
        ++pos;
        CHECK(9 == *pos);
        ++pos;
        CHECK(8 == *pos);
        ++pos;
        CHECK(7 == *pos);

        auto coll3 = std::stack<Buffer>{};
        auto bufs  = std::vector{genRandBuffer(10, 20), genRandBuffer(30, 50)};
        CHECK(bufs.size() == 2);
        CHECK(!bufs[0].empty());
        CHECK(!bufs[1].empty());

        splice(coll3, std::move(bufs));

        CHECK(bufs.size() == 2);
        CHECK(bufs[0].empty());
        CHECK(bufs[1].empty());
    }

    {
        auto coll = Map<int, std::string>{};
        LOOP (i, 100)
        {
            insert(coll, i, tos(i + 10000));
        }

        CHECK(coll.size() == 100);

        for (auto const& [key, mapped] : coll)
        {
            CHECK(mapped == tos(key + 10000));
        }

        LOOP (i, 100)
        {
            auto const nh = query(coll, i);
            CHECK(nh);
            CHECK(i == nh.key());
            CHECK(tos(i + 10000) == nh.mapped());
        }
    }

    {
        auto coll = Multimap<int, std::string>{};
        LOOP (i, 100)
        {
            insert(coll, i, tos(i + 10000));
            insert(coll, i, tos(i + 10000));
        }

        CHECK(coll.size() == 200);

        for (auto const& [key, mapped] : coll)
        {
            CHECK(mapped == tos(key + 10000));
        }

        LOOP (i, 100)
        {
            auto const nh = query(coll, i);
            CHECK(nh);
            CHECK(i == nh.key());
            CHECK(tos(i + 10000) == nh.mapped());
        }
    }

    {
        auto coll = UnorderedMap<int, std::string>{};
        LOOP (i, 100)
        {
            insert(coll, i, tos(i + 10000));
        }

        CHECK(coll.size() == 100);

        LOOP (i, 100)
        {
            CHECK(coll[i] == tos(i + 10000));
        }

        LOOP (i, 100)
        {
            auto const nh = query(coll, i);
            CHECK(nh);
            CHECK(i == nh.key());
            CHECK(tos(i + 10000) == nh.mapped());
        }
    }

    {
        auto coll = UnorderedMultimap<int, std::string>{};
        LOOP (i, 100)
        {
            insert(coll, i, tos(i + 10000));
            insert(coll, i, tos(i + 10000));
        }

        CHECK(coll.size() == 200);

        for (auto const& [key, mapped] : coll)
        {
            CHECK(mapped == tos(key + 10000));
        }

        LOOP (i, 100)
        {
            auto const nh = query(coll, i);
            CHECK(nh);
            CHECK(i == nh.key());
            CHECK(tos(i + 10000) == nh.mapped());
        }
    }

    {
        auto coll = Set<std::string>{};
        LOOP (i, 100)
        {
            auto str = std::string{};
            LOOP_N (rand(2, 100))
            {
                insert(str, rand<char>('a', 'z'));
            }
            CHECK(str.size() >= 2 && str.size() <= 100);
            insert(coll, std::move(str));
            insert(coll, tos(i));
        }

        CHECK(coll.size() == 200);

        LOOP (i, 100)
        {
            auto const s  = tos(i);
            auto const sv = tosv(s);
            auto const nh = query(coll, sv);
            CHECK(nh);
            CHECK(sv == nh.value());
        }

        CHECK(!query(coll, "ABC"sv));
    }

    {
        auto coll = Multiset<std::string>{};
        LOOP (i, 100)
        {
            auto str = std::string{};
            LOOP_N (rand(2, 100))
            {
                insert(str, rand<char>('a', 'z'));
            }
            CHECK(str.size() >= 2 && str.size() <= 100);
            insert(coll, std::move(str));
            insert(coll, tos(i));
            insert(coll, tos(i));
        }

        CHECK(coll.size() == 300);

        LOOP (i, 100)
        {
            auto const s  = tos(i);
            auto const sv = tosv(s);
            auto const nh = query(coll, sv);
            CHECK(nh);
            CHECK(sv == nh.value());
        }

        CHECK(!query(coll, "ABC"sv));
    }

    {
        auto coll = UnorderedSet<std::string>{};
        LOOP (i, 100)
        {
            auto str = std::string{};
            LOOP_N (rand(2, 100))
            {
                insert(str, rand<char>('a', 'z'));
            }
            CHECK(str.size() >= 2 && str.size() <= 100);
            insert(coll, std::move(str));
            insert(coll, tos(i));
        }

        CHECK(coll.size() == 200);

        LOOP (i, 100)
        {
            auto const s  = tos(i);
            auto const sv = tosv(s);
            auto const nh = query(coll, sv);
            CHECK(nh);
            CHECK(sv == nh.value());
        }

        CHECK(!query(coll, "ABC"sv));
    }

    {
        auto coll = UnorderedMultiset<std::string>{};
        LOOP (i, 100)
        {
            auto str = std::string{};
            LOOP_N (rand(2, 100))
            {
                insert(str, rand<char>('a', 'z'));
            }
            CHECK(str.size() >= 2 && str.size() <= 100);
            insert(coll, std::move(str));
            insert(coll, tos(i));
            insert(coll, tos(i));
        }

        CHECK(coll.size() == 300);

        LOOP (i, 100)
        {
            auto const s  = tos(i);
            auto const sv = tosv(s);
            auto const nh = query(coll, sv);
            CHECK(nh);
            CHECK(sv == nh.value());
        }

        CHECK(!query(coll, "ABC"sv));
    }

    {
        auto const src = std::vector{
            std::vector{1, 2, 3}, std::vector{4, 5, 6}, std::vector{7, 8, 9}};

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 3);
        CHECK(src[1].size() == 3);
        CHECK(src[2].size() == 3);

        auto const dst = ranges::to<std::deque>(src);

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 3);
        CHECK(src[1].size() == 3);
        CHECK(src[2].size() == 3);
        CHECK(src[0] == std::vector{1, 2, 3});
        CHECK(src[1] == std::vector{4, 5, 6});
        CHECK(src[2] == std::vector{7, 8, 9});
        CHECK(dst.size() == 3);

        auto pos = dst.begin();
        CHECK(*pos++ == std::vector{1, 2, 3});
        CHECK(*pos++ == std::vector{4, 5, 6});
        CHECK(*pos++ == std::vector{7, 8, 9});
        CHECK(pos == dst.end());
    }

    {
        auto src = std::vector{
            std::vector{1, 2, 3}, std::vector{4, 5, 6}, std::vector{7, 8, 9}};

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 3);
        CHECK(src[1].size() == 3);
        CHECK(src[2].size() == 3);

        auto const dst = src | views::move | ranges::to<std::deque>;

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 0);
        CHECK(src[1].size() == 0);
        CHECK(src[2].size() == 0);
        CHECK(dst.size() == 3);

        auto pos = dst.begin();
        CHECK(*pos++ == std::vector{1, 2, 3});
        CHECK(*pos++ == std::vector{4, 5, 6});
        CHECK(*pos++ == std::vector{7, 8, 9});
        CHECK(pos == dst.end());
    }

    {
        auto const src = std::vector{
            std::vector{1, 2, 3}, std::vector{4, 5, 6}, std::vector{7, 8, 9}};

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 3);
        CHECK(src[1].size() == 3);
        CHECK(src[2].size() == 3);

        auto const dst = ranges::to<std::deque>(src);

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 3);
        CHECK(src[1].size() == 3);
        CHECK(src[2].size() == 3);
        CHECK(src[0] == std::vector{1, 2, 3});
        CHECK(src[1] == std::vector{4, 5, 6});
        CHECK(src[2] == std::vector{7, 8, 9});
        CHECK(dst.size() == 3);

        auto pos = dst.begin();
        CHECK(*pos++ == std::vector{1, 2, 3});
        CHECK(*pos++ == std::vector{4, 5, 6});
        CHECK(*pos++ == std::vector{7, 8, 9});
        CHECK(pos == dst.end());
    }

    {
        auto src = std::vector{
            std::vector{1, 2, 3}, std::vector{4, 5, 6}, std::vector{7, 8, 9}};

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 3);
        CHECK(src[1].size() == 3);
        CHECK(src[2].size() == 3);

        auto const dst = src | views::move | ranges::to<std::deque>;

        CHECK(src.size() == 3);
        CHECK(src[0].size() == 0);
        CHECK(src[1].size() == 0);
        CHECK(src[2].size() == 0);
        CHECK(dst.size() == 3);

        auto pos = dst.begin();
        CHECK(*pos++ == std::vector{1, 2, 3});
        CHECK(*pos++ == std::vector{4, 5, 6});
        CHECK(*pos++ == std::vector{7, 8, 9});
        CHECK(pos == dst.end());
    }

    {
        auto coll = UnorderedMultiset<std::string>{};
        LOOP (i, 100)
        {
            auto str = genRandString(100, 200) | views::cref |
                       views::drop('2') | views::drop('3') | views::drop('6') |
                       views::drop('7') | ranges::to<std::string>;
            insert(coll, std::move(str));
            insert(coll, tos(i));
            insert(coll, tos(i));
        }

        CHECK(coll.size() == 300);

        auto nh = extract(coll, "23"sv);
        CHECK(nh);
        CHECK(nh.value() == "23"sv);
        CHECK(coll.size() == 299);

        insert(coll, std::move(nh));
        CHECK(coll.size() == 300);

        CHECK(!query(coll, "ABC"sv));

        eraseAll(coll, "7"sv);
        CHECK(coll.size() == 298);

        eraseIf(coll, "33"sv == _1 || "66"sv == _1);
        CHECK(coll.size() == 294);
    }

    {
        auto coll = std::list<int>{};
        LOOP (i, 100)
        {
            insert(coll, i);
        }

        CHECK(coll.size() == 100);
        eraseIf(coll, _1 % 2);
        CHECK(coll.size() == 50);
    }
}